package utils

import (
	"GameServer/Common/data"
	"GameServer/Common/workpool"
	"encoding/json"
	"io/ioutil"
	"math/rand"
	"runtime/debug"
	"time"

	log "github.com/sirupsen/logrus"
)

//时间转换的模板，golang里面只能是 "2006-01-02 15:04:05" （go的诞生时间）
var TIME_LAYOUT string = "2006-01-02 15:04:05"

// 时区
var tLocation *time.Location

// 设置时区
func SetLocation(name string) (err error) {
	if name == "" {
		tLocation = time.Local // 获取当地时区
		return
	}
	tLocation, err = time.LoadLocation(name) // 设置时区，例："UTC"
	return
}

// 字符串转时间
func LayoutToTime(value string) (t time.Time, err error) {
	t, err = time.ParseInLocation(TIME_LAYOUT, value, tLocation)
	return
}

// 时间转字符串
func TimeToLayout(t time.Time) (layout string) {
	layout = t.Format(TIME_LAYOUT)
	return
}

// 凌晨时间，时区
func ZeroTime(t time.Time) (r int64) {
	r = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, tLocation).Unix()
	return
}

// 现在时间，时区
func TNow() (r time.Time) {
	r = time.Now().In(tLocation)
	return
}

// Unix时间戳转时间，时区
func TTime(t1, t2 int64) (r time.Time) {
	r = time.Unix(t1, t2).In(tLocation)
	return
}

// 同一天
func IsSameDay(t1, t2 int64) bool {
	y1, m1, d1 := TTime(t1, 0).Date()
	y2, m2, d2 := TTime(t2, 0).Date()
	return y1 == y2 && m1 == m2 && d1 == d2
}

// json路径
var JsonConfDir string = "data/json"

func SetJsonConfDir(pathstr string) {
	JsonConfDir = pathstr
}

func ReadJsonFile(filename string) (b []byte, err error) {
	b, err = ioutil.ReadFile(JsonConfDir + "/" + filename)
	return
}

func RandomWeightKV(list0 []data.WeightKV) data.WeightKV {
	var (
		sum  uint64
		list []data.WeightV
	)
	list0 = ReorderWeightKVList(list0)
	for _, item := range list0 {
		sum += item.Weight
		list = append(list, data.WeightV{Weight: sum, Value: item})
	}
	result, _ := randomWeight(list, sum)
	return result.Value.(data.WeightKV)
}

// 随机权重值，返回结果，和index
func RandomWeightKVReturnIndex(list0 []data.WeightV) (result data.WeightV, index int64) {
	var (
		sum  uint64
		list []data.WeightV
	)

	list0 = ReorderWeightVList(list0)
	for _, item := range list0 {
		sum += item.Weight
		list = append(list, data.WeightV{Weight: sum, Value: item})
	}
	r, index := randomWeight(list, sum)
	result = r.Value.(data.WeightV)

	return result, index
}

func RandomWeight(list0 []data.WeightV) data.WeightV {
	var (
		sum  uint64
		list []data.WeightV
	)
	list0 = ReorderWeightVList(list0)
	for _, item := range list0 {
		sum += item.Weight
		if item.Weight != 0 {
			item.Weight = sum
		}
		list = append(list, item)
	}

	result, _ := randomWeight(list, sum)

	return result
}

func randomWeight(list []data.WeightV, sum uint64) (result data.WeightV, index int64) {
	val := uint64(rand.Int63n(int64(sum)))
	// log.WithFields(log.Fields{
	// 	"val": val,
	// 	"sum": sum,
	// }).Debug("概率算法随机结果收集")
	for i, item := range list {
		if item.Weight == 0 {
			continue
		}
		// log.WithFields(log.Fields{
		// 	"val":         val,
		// 	"sum":         sum,
		// 	"i":           i,
		// 	"item.Weight": item.Weight,
		// }).Debug("概率算法随机结果收集")
		if item.Weight >= val {
			result = item
			index = int64(i)
			return result, index
		}
	}
	result = list[0]
	index = 0
	return result, index
}

// 取[min, max]区间的随机数
func RandomInt(min, max int) int {
	if min > max {
		min, max = max, min
	}
	return rand.Intn(max-min+1) + min
}

// 取[min, max]区间的随机数
func RandomInt32(min, max int32) int32 {
	if min > max {
		min, max = max, min
	}
	return rand.Int31n(max-min+1) + min
}

// 取[min, max]区间的随机数
func RandomInt64(min, max int64) int64 {
	if min >= max {
		return max
	}
	return rand.Int63n(max-min+1) + min
}

func RandomList(list []interface{}) (r interface{}) {
	index := RandomInt64(0, int64(len(list))-1)
	return list[index]
}

func ConvertStructByJson(src interface{}, dst interface{}) (err error) {
	b, err := json.Marshal(src)
	if err != nil {
		return
	}
	err = json.Unmarshal(b, &dst)
	return
}

func Obj2JsonStr(obj interface{}) (r string) {
	b, err := json.Marshal(obj)
	if err != nil {
		panic("obj2json str err:" + err.Error())
	}
	r = string(b)
	return
}

func AsyncFunc(f func()) {
	f1 := func() {
		defer func() {
			if err := recover(); err != nil {
				log.Error("stacktrace from panic gofunc func: \n", string(debug.Stack()))
			}
		}()
		f()
	}
	workpool.Do(f1)

}

//依据总数和组数生成下一组随机数值
func GenerateNextGroupNum(sum int64, groupCount int64, limit int64) int64 {
	if sum <= 0 {
		return sum
	}
	layerNum := sum / groupCount
	maxNum := sum % groupCount
	num := layerNum + RandomInt64(0, maxNum)
	if limit > 0 && num > limit {
		num = limit
	}
	/*log.WithFields(log.Fields{
		"sum":        sum,
		"groupCount": groupCount,
		"num":        num,
		"limit":      limit,
	}).Debug("测试代码,generateNextGroupNum")*/
	return num
}

//每层随机生成星星、电视机、炸弹、许愿球的数量
func GenerateGroupNum(arrLen int, genNum int64) (arrNum []int64) {
	if arrLen <= 0 {
		/*log.WithFields(log.Fields{
			"arrLen": arrLen,
			"genNum": genNum,
		}).Debug("测试代码,GenerateGroupNum")*/
		return
	}
	arrNum = make([]int64, arrLen)
	if genNum <= 0 {
		return
	}
	avgNum := genNum / int64(arrLen) //平均的数量
	spsNum := genNum % int64(arrLen) //剩余的数量
	//平均的数量大于1 扣除1个 拿去随机
	if avgNum > 1 {
		avgNum = avgNum - 1
		spsNum = spsNum + int64(arrLen)
	}
	//数组的基础数量
	for idx := 0; idx < arrLen; idx++ {
		arrNum[idx] = avgNum
	}
	//将未分配的数 随机到数组中
	for i := int64(0); i < spsNum; i++ {
		idx := RandomInt(0, arrLen-1)
		arrNum[idx]++
	}
	return
}

//使用KnuthShuffle算法对WeightKV列表进行乱序
func KnuthShuffleForWeightKV(list0 []data.WeightKV) []data.WeightKV {
	arrIndexMax := len(list0) - 1
	var temp data.WeightKV
	var index int
	rand.Seed(time.Now().UnixNano())
	for i := arrIndexMax; i >= 0; i-- {
		index = rand.Intn(i + 1)
		temp = list0[index] //取[0,i+1)间的随机数
		list0[index] = list0[i]
		list0[i] = temp
		/*
			log.WithFields(log.Fields{
				"index": index,
				"i":     i,
			}).Debug("概率算法随机结果收集")
		*/
	}
	return list0
}

//重排列WeightKV列表
func ReorderWeightKVList(list0 []data.WeightKV) []data.WeightKV {
	list0 = MergeSort(list0, 0, len(list0)-1)
	return list0
}

//归并排序
func MergeSort(arr []data.WeightKV, start int, end int) []data.WeightKV {
	if start >= end {
		return arr
	}
	i := start
	mid := (start + end) / 2
	j := mid + 1
	arr = MergeSort(arr, i, mid)
	arr = MergeSort(arr, j, end)

	temp := make([]data.WeightKV, end-start+1)
	index := 0
	for i <= mid && j <= end {
		if arr[i].Weight <= arr[j].Weight {
			temp[index] = arr[i]
			i += 1
		} else {
			temp[index] = arr[j]
			j += 1
		}
		index += 1
	}
	for i <= mid {
		temp[index] = arr[i]
		index += 1
		i += 1
	}
	for j <= end {
		temp[index] = arr[j]
		index += 1
		j += 1
	}
	for k := start; k <= end; k++ {
		arr[k] = temp[k-start]
	}

	return arr
}

//重排列WeightKV列表
func ReorderWeightVList(list0 []data.WeightV) []data.WeightV {
	var list = MergeSortWeightV(list0, 0, len(list0)-1)
	return list
}

//归并排序
func MergeSortWeightV(arr []data.WeightV, start int, end int) []data.WeightV {
	if start >= end {
		return arr
	}
	i := start
	mid := (start + end) / 2
	j := mid + 1
	arr = MergeSortWeightV(arr, i, mid)
	arr = MergeSortWeightV(arr, j, end)

	temp := make([]data.WeightV, end-start+1)
	index := 0
	for i <= mid && j <= end {
		if arr[i].Weight <= arr[j].Weight {
			temp[index] = arr[i]
			i += 1
		} else {
			temp[index] = arr[j]
			j += 1
		}
		index += 1
	}
	for i <= mid {
		temp[index] = arr[i]
		index += 1
		i += 1
	}
	for j <= end {
		temp[index] = arr[j]
		index += 1
		j += 1
	}
	for k := start; k <= end; k++ {
		arr[k] = temp[k-start]
	}

	return arr
}

func RandomEntr() (r int64) {
	r = rand.Int63n(2) * rand.Int63n(2) * rand.Int63n(151)
	return
}
